package websocket

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"log"
	"os"
	"path"
	"strings"
	"time"
	"tuiwen-go/internal/api"
	"tuiwen-go/internal/config"
	"tuiwen-go/internal/db"
	"tuiwen-go/internal/utils"
)

func taskAudioByComfyuiHandler(c *Client, data json.RawMessage) {
	log.Printf("Client %s: Handling Audio Task, Data: %s", c.ID, string(data))

	var taskData struct {
		ProjectID string `json:"project_id"`
		Id        string `json:"id"`
	} // Assuming the data contains project_id and project_name

	if err := json.Unmarshal(data, &taskData); err != nil {
		log.Printf("Client %s: Error unmarshalling audio task data: %v", c.ID, err)
		sendMessage(c, api.WxJSONResponse{Code: -1, Msg: "Invalid audio task data format"})
		return
	}

	if taskData.ProjectID == "" {
		sendMessage(c, api.WxJSONResponse{Code: -1, Msg: "项目ID不能为空"})
		return
	}

	// Fetch text entries that need audios generated
	sqlQuery := "SELECT id, content, audio FROM text WHERE project_id = ? AND content IS NOT NULL"
	args := []interface{}{taskData.ProjectID}
	if taskData.Id != "" {
		sqlQuery += " AND id = ?"
		args = append(args, taskData.Id)
	} else {
		sqlQuery += " AND (audio IS NULL OR audio = '')"
	}
	rows, err := db.Query(sqlQuery, args...)
	if err != nil {
		log.Printf("Client %s: Error querying text for audio task: %v", c.ID, err)
		sendMessage(c, api.WxJSONResponse{Code: -1, Msg: "查询待生成音频文本失败"})
		return
	}
	defer rows.Close()

	var textsToAudio []struct {
		ID      int
		Content string
		Audio   string // Add audio field
	}

	for rows.Next() {
		var id int
		var content string
		var audio sql.NullString // Scan the audio column
		err := rows.Scan(&id, &content, &audio)
		if err != nil {
			log.Printf("Client %s: Error scanning text row for audio task: %v", c.ID, err)
			continue
		}

		textsToAudio = append(textsToAudio, struct {
			ID      int
			Content string
			Audio   string
		}{ID: id, Content: content, Audio: audio.String})

	}

	if err = rows.Err(); err != nil {
		log.Printf("Client %s: Error iterating text rows for audio task: %v", c.ID, err)
		sendMessage(c, api.WxJSONResponse{Code: -1, Msg: "处理待生成音频文本失败"})
		return
	}

	if len(textsToAudio) == 0 {
		sendMessage(c, api.WxJSONResponse{Code: 0, Msg: "音频已全部生成"})
		return // No texts to generate audios for
	}

	// Process each text entry to generate audio
	for _, item := range textsToAudio {
		generatedAudio, audio_comfyui, err := generateAndSaveAudioByComfyui(item.Content, item.Audio, taskData.ProjectID)
		if err != nil {
			log.Printf("Client %s: Error generating and saving audio for text ID %d: %v", c.ID, item.ID, err)
			// Continue processing other items, but log the error
			sendMessage(c, api.WxJSONResponse{Code: 1, Msg: fmt.Sprintf("音频生成失败 (ID: %d): %v", item.ID, err)})
		} else {

			// Update the database with the generated audio path
			sqlUpdate := "UPDATE text SET audio = ?, audio_comfyui = ? WHERE project_id = ? AND id = ?"
			_, err := db.Exec(sqlUpdate, generatedAudio, audio_comfyui, taskData.ProjectID, item.ID)
			if err != nil {
				log.Printf("Client %s: Error updating audio for text ID %d: %v", c.ID, item.ID, err)
				// Continue processing other items, but log the error
			} else {

				// 旧音频重命名，格式为：新音频名_旧音频名.png
				if item.Audio != "" {
					oldAudioPath := strings.ReplaceAll(item.Audio, "/public", "./public")
					newAudioFilename := path.Base(generatedAudio)
					oldAudioFilename := path.Base(oldAudioPath)
					newOldAudioName := strings.TrimSuffix(newAudioFilename, path.Ext(newAudioFilename)) + "_" + oldAudioFilename
					oldAudioDir := path.Dir(oldAudioPath)
					newOldAudioPath := path.Join(oldAudioDir, newOldAudioName)

					log.Printf("Client %s: Renaming old audio file from %s to %s", c.ID, oldAudioPath, newOldAudioPath)
					err := os.Rename(oldAudioPath, newOldAudioPath)
					if err != nil {
						log.Printf("Client %s: Failed to rename old audio file %s to %s: %v", c.ID, oldAudioPath, newOldAudioPath, err)
					}
				}
				// Send a message to the client with the updated audio URL
				sendMessage(c, api.WxJSONResponse{
					Code: 1, // Or a specific code for audio update
					Msg:  fmt.Sprintf("音频生成成功 (ID: %d)", item.ID),
					Data: map[string]interface{}{
						"id":         item.ID,
						"audio_path": generatedAudio,
					},
				})
			}
		}
	}

	// A final success message after attempting all updates (optional, as individual messages are sent)
	// sendMessage(c, api.WxJSONResponse{Code: 0, Msg: "音频生成任务完成"})
}

// generateAndSaveAudioByComfyui calls the ComfyUI API, saves the audio, and returns the public path.
func generateAndSaveAudioByComfyui(content string, audioPath string, projectID string) (string, string, error) {
	log.Printf("Generating audio for prompt: %s (Project ID: %s)", content, projectID)

	// 1. Load the ComfyUI API prompt template
	promptTemplatePath, ok := config.GetSetting("comfyui_audio_template_path")
	if !ok || promptTemplatePath == "" {
		promptTemplatePath = "templates/comfyuiApiJson/生成音频.json"
	}

	exeutableDir, err := os.Executable()
	if err != nil {
		return "", "", fmt.Errorf("error getting executable directory: %v", err)
	}
	jsonFilePath := path.Join(path.Dir(exeutableDir), promptTemplatePath)

	jsonFile, err := os.ReadFile(jsonFilePath)
	if err != nil {
		return "", "", fmt.Errorf("error reading comfyui api json file: %v", err)
	}

	var promptData map[string]interface{}
	if err := json.Unmarshal(jsonFile, &promptData); err != nil {
		return "", "", fmt.Errorf("error unmarshalling comfyui api json: %v", err)
	}

	// 2. Modify the prompt with dynamic values
	// Example: Find the node for text prompt and update it.
	// This needs to be adapted based on the actual structure of your JSON template.
	promptNodeID, ok := config.GetSetting("comfyUI_content_node_id")
	if !ok {
		promptNodeID = "11"
	}

	if node, ok := promptData[promptNodeID].(map[string]interface{}); ok {
		if inputs, ok := node["inputs"].(map[string]interface{}); ok {
			inputs["multi_line_prompt"] = content
		} else {
			return "", "", fmt.Errorf("invalid comfyui template structure: 'inputs' not found or not a map")
		}
	} else {
		return "", "", fmt.Errorf("invalid comfyui template structure: node '%s' not found or not a map", promptNodeID)
	}

	comfyUI_imgUpload_node_id, ok := config.GetSetting("comfyUI_audioUpload_node_id")
	if !ok {
		comfyUI_imgUpload_node_id = "62"
	}

	if node, ok := promptData[comfyUI_imgUpload_node_id].(map[string]interface{}); ok {
		if inputs, ok := node["inputs"].(map[string]interface{}); ok {

			inputs["audio"] = "大家好我是你的温柔知性女友.wav"
			// 根据projectid查询speaker sound
			var speakerSound string
			err = db.DB.QueryRow("SELECT sound FROM project p LEFT JOIN speaker s on p.speaker_id=s.id WHERE p.id = ?", projectID).Scan(&speakerSound)
			if err != nil {
				log.Printf("获取讲述人声音失败: %v", err)
				return "", "", fmt.Errorf("获取讲述人声音失败")
			}
			inputs["audio"] = speakerSound
		} else {
			return "", "", fmt.Errorf("invalid comfyui template structure: 'inputs' not found or not a map")
		}
	} else {
		return "", "", fmt.Errorf("invalid comfyui template structure: node '%s' not found or not a map", comfyUI_imgUpload_node_id)
	}

	// 3. Call the ComfyUI API
	outputAudios, audio_comfyui, err := utils.GetAudios(promptData)
	if err != nil {
		return "", "", fmt.Errorf("error getting audios from comfyui: %v", err)
	}

	// 4. Find the output audio from the 'Saveaudio' node
	var audioData []byte
	found := false
	for _, nodeOutput := range outputAudios {
		if len(nodeOutput) > 0 {
			audioData = nodeOutput[0] // Assuming the first audio is the one we want
			found = true
			break
		}
	}

	if !found || len(audioData) == 0 {
		return "", "", fmt.Errorf("no audios returned from ComfyUI")
	}

	// 5. Save the audio
	dir := fmt.Sprintf("public/audios/%s", projectID)
	saveDir := path.Join(path.Dir(exeutableDir), dir)

	if _, err := os.Stat(saveDir); os.IsNotExist(err) {
		err = os.MkdirAll(saveDir, 0755)
		if err != nil {
			return "", "", fmt.Errorf("error creating directory %s: %v", saveDir, err)
		}
	}

	filename := fmt.Sprintf("%d.wav", time.Now().UnixNano())
	savePath := path.Join(saveDir, filename)

	err = os.WriteFile(savePath, audioData, 0644)
	if err != nil {
		return "", "", fmt.Errorf("error saving audio file %s: %v", savePath, err)
	}

	publicPath := path.Join("audios", projectID, filename)
	publicPath = strings.ReplaceAll(publicPath, "\\", "/")

	log.Printf("Audio saved to %s, public path: %s", savePath, publicPath)

	return "/public/" + publicPath, audio_comfyui, nil
}
